//
//  DownloadTask.swift
//  TestActorDownload
//
//  Created by rolodestar on 2025/6/13.
//
import Foundation
import SwiftData
enum DownladStatus: String, Codable { case queued, downloading, paused, completed }
@MainActor protocol DownloadTaskForSwiftDataDelegate where Self: PersistentModel,Self: DownloadTaskForSwiftDataProtocol{
    func updateDownload(id: UUID,withFinished localFilePath: URL?)
    func updateDownloadProgress(id: UUID,didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
    func updateDownloadStatus(id: UUID,withStatus status: DownladStatus,resumeData: Data? )
    func getResumeData() -> Data?
    func saveModel()
    func removeLocalFile(id: UUID)
    func fileIsExist() -> Bool
}
extension DownloadTaskForSwiftDataDelegate{
    func saveModel() {
        if modelContext != nil {
            do{
                try modelContext!.save()
            }catch{
                print(error)
            }
        }
    }
    func fileIsExist() -> Bool{
        guard let localFilePath = localStoredFilePath else { return false }
        return FileManager.default.fileExists(atPath: localFilePath.path())
    }
    
    func removeLocalFile(id: UUID){
        guard fileIsExist() else { return }
        do{
            try FileManager.default.removeItem(at: localStoredFilePath!)
            let fetchDes = FetchDescriptor<Self>(
                predicate: #Predicate { $0.id == id }
            )
            guard var model =  try self.modelContext?.fetch(fetchDes).first else { return }
            model.localStoredFilePath = nil
            model.currentProcess = 0
            model.status = .queued
            saveModel()
        }catch{
            print(error)
            return
        }
    }
    func updateDownloadStatus(id: UUID, withStatus status: DownladStatus,resumeData: Data? = nil){
        do{
            let fetchDes = FetchDescriptor<Self>(
                predicate: #Predicate { $0.id == id }
            )
            guard var model =  try self.modelContext?.fetch(fetchDes).first else { return }
            model.status = status
            model.resumeData = resumeData
            saveModel()
        }catch{
            print(error)
            return
        }
       
    }
    
    func updateDownload(id: UUID, withFinished localFilePath: URL?) {
        do{
            let fetchDes = FetchDescriptor<Self>(
                predicate: #Predicate { $0.id == id }
            )
            guard var model =  try self.modelContext?.fetch(fetchDes).first else { return }
            model.localStoredFilePath = localFilePath
            model.currentProcess = 1.0
            saveModel()
        }catch{
            print(error)
            return
        }
        
    }
    
    func updateDownloadProgress(id: UUID, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        do{
            let fetchDes = FetchDescriptor<Self>(
                predicate: #Predicate { $0.id == id }
            )
            guard var model =  try self.modelContext?.fetch(fetchDes).first else { return }
            model.currentProcess = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite)
            saveModel()
        }catch{
            print(error)
            return
        }
       
    }
    
    func getResumeData() -> Data? {
        return resumeData
    }
}

protocol DownloadTaskForSwiftDataProtocol {
    var id: UUID {get set}
    var remoteURL: URL {get set}
    var localStoredFilePath: URL? {get set}// 本地存储路径
    var status: DownladStatus {get set}// 下载状态（排队、下载中、暂停、完成）
    var resumeData: Data? {get set}// 断点续传数据
    var currentProcess: Double {get set}// 当前下载进度
}

class DownloadTask: NSObject {
    public let id: UUID
    public let remoteURL: URL
    private  var session: URLSession
    private var downloadTask: URLSessionDownloadTask?
    public var resumeData: Data? // 断点数据
    public var swiftDataDelegate: (any DownloadTaskForSwiftDataDelegate)?
    public var downloadFilePath: URL //文件存储路径，不含文件名
    public var suggestFileName: String //建议文件名，不含路径
//    var modelContext: ModelContext?
//    private var session: URLSession
    
    init(id: UUID, remoteURL: URL ,swifDataDelegate: (any DownloadTaskForSwiftDataDelegate)? = nil,downloadFilePath: URL? = nil,suggestFileName: String = "") {
        self.id = id
        self.remoteURL = remoteURL
        self.swiftDataDelegate = swifDataDelegate
        self.downloadTask = nil
        self.resumeData = nil
        if downloadFilePath == nil {
            self.downloadFilePath =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        }else{
            self.downloadFilePath = downloadFilePath!
        }
        if !suggestFileName.isEmpty {
            self.suggestFileName = suggestFileName
        }else{
            self.suggestFileName = "\(id.uuidString).mp4"
        }
        let  config = URLSessionConfiguration.default
       session = URLSession(configuration: config)
        super.init()
        Task{
            await MainActor.run {
                swifDataDelegate?.updateDownloadStatus(id: id ,withStatus: .queued)
            }
            
        }
    }
    init(model: any DownloadTaskForSwiftDataDelegate) {
        self.id = model.id
        self.remoteURL = model.remoteURL
        self.swiftDataDelegate = model
        self.resumeData = model.resumeData
        if let localFile = model.localStoredFilePath{
            let path = localFile.path
            let fileName = localFile.lastPathComponent
            self.downloadFilePath = URL(fileURLWithPath: path, isDirectory: true)
            self.suggestFileName = fileName
        }else{
            self.downloadFilePath =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            self.suggestFileName = "\(id.uuidString).mp4"
        }
       
        let  config = URLSessionConfiguration.default
       session = URLSession(configuration: config)
//        self.modelContext = modelContext

        super.init()
        checkModelIsDownloadAndUpdate(model: model)
        Task{
            await MainActor.run {
                swiftDataDelegate?.updateDownloadStatus(id: id ,withStatus: .queued)
            }
            
        }
        
    }
    
    func checkModelIsDownloadAndUpdate(model: any DownloadTaskForSwiftDataDelegate){
        if fileIsExist {
            Task{
                await MainActor.run {
                    let storedFilePath = downloadFilePath.appendingPathComponent(suggestFileName)
                    //                model.localStoredFilePath = storedFilePath
                    model.updateDownloadStatus(id: id, withStatus: .completed)
                    model.updateDownload(id: id, withFinished: storedFilePath)
                    
                    
                }
                
            }
        }else{
            Task{
                await MainActor.run {
                    
                    model.updateDownloadStatus(id: id, withStatus: .queued)
                    model.updateDownload(id: id, withFinished: nil)
                    
                    
                }
                
            }
        }
       
        
    }
    var fileIsExist: Bool{
        return FileManager.default.fileExists(atPath: downloadFilePath.appendingPathComponent(suggestFileName).path)
    }
    func start() async throws {
        if fileIsExist {return}
        downloadTask = session.downloadTask(with: remoteURL)
        downloadTask?.delegate = self
        downloadTask?.resume()
        Task{
            await MainActor.run {
                swiftDataDelegate?.updateDownloadStatus(id: id ,withStatus: .downloading)
            }
            
        }
    }
    
    func pause() async {
        if fileIsExist {return}
        let  resumeData =  await downloadTask?.cancelByProducingResumeData()
        self.resumeData = resumeData
        Task{
            await MainActor.run {
                swiftDataDelegate?.updateDownloadStatus(id: id ,withStatus: .paused,resumeData: resumeData)
            }
            
        }
    }
    
   func resume() async throws {
       if fileIsExist {return}
        Task{
           
            let resumeData = await MainActor.run {
                if let data = swiftDataDelegate?.getResumeData()//(id: id ,withStatus: .downloading ,modelContext: modelContext)
                {
                    swiftDataDelegate?.updateDownloadStatus(id: id ,withStatus: .downloading)
                    return data
                    
                }else{
                    return  Data()
                }
            }
            //MARK: 不能恢复，待fix
            guard   resumeData.count != 0 else { return }
//            if downloadTask == nil {
//                downloadTask = session.downloadTask(with: remoteURL)
////                session.res÷u
//                downloadTask?.delegate = self
//                session.downloadTask(withResumeData: resumeData)
//            
//            }
//            session.download
//            downloadTask?.reu
            downloadTask = session.downloadTask(withResumeData: resumeData)
            downloadTask?.delegate = self
            downloadTask?.resume()
            
        }
    }
    
    // 保存下载文件到 Documents
    private func saveFile(localTempFile: URL) throws -> URL {
        
        let destURL = self.downloadFilePath.appendingPathComponent(suggestFileName)
        if FileManager.default.fileExists(atPath: destURL.path()){
            return destURL
        }
        try FileManager.default.moveItem(at: localTempFile, to: destURL)
        return destURL
    }
    
}

// MARK: - URLSessionDownloadDelegate 处理下载事件
extension DownloadTask: URLSessionDownloadDelegate {
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        do {
            if let suggestedFileName = downloadTask.response?.suggestedFilename{
                self.suggestFileName = suggestedFileName
            }
            let savedPath = try saveFile(localTempFile: location)
            Task{
                await MainActor.run {
                    swiftDataDelegate?.updateDownload(id: id, withFinished: savedPath)
                    swiftDataDelegate?.updateDownloadStatus(id: id ,withStatus: .completed)
                }
                
            }
            // 更新 SwiftData 模型
            
        } catch {
            print("保存失败: \(error)")
            Task{
                await MainActor.run {
                    swiftDataDelegate?.updateDownload(id: id, withFinished: nil)
                    swiftDataDelegate?.updateDownloadStatus(id: id ,withStatus: .completed)
                }
                
            }
            
        }
    }
    
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
        let progress = Double( Float(totalBytesWritten) / Float(totalBytesExpectedToWrite))
        // 通知 UI 更新进度（通过 Combine 或 AsyncStream）
//        viewThread(at: "task url delegate progress")
        Task{
            await MainActor.run {
                swiftDataDelegate?.updateDownloadProgress(id: id,didWriteData:bytesWritten, totalBytesWritten: totalBytesWritten ,totalBytesExpectedToWrite:totalBytesExpectedToWrite)
            }
            
        }
            
        print(progress)
    }
}
